package com.haoze.nurse.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.haoze.common.config.RedisUtil;
import com.haoze.common.enumeration.StateEnum;
import com.haoze.common.exception.ServiceException;
import com.haoze.common.response.Result;
import com.haoze.common.response.ResultGenerator;
import com.haoze.common.utils.Tree;
import com.haoze.common.utils.UUIDUtil;
import com.haoze.nurse.dao.*;
import com.haoze.nurse.dto.Element;
import com.haoze.nurse.enumeration.*;
import com.haoze.nurse.feign.RuleService;
import com.haoze.nurse.model.*;
import com.haoze.nurse.service.EmrNurseStatisticsService;
import com.haoze.nurse.service.FileIndexService;
import com.haoze.nurse.vo.*;
import oracle.sql.TIMESTAMP;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
import tk.mybatis.mapper.entity.Condition;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.sql.Clob;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.IntStream;


@Service
public class FileIndexServiceImpl implements FileIndexService {

    private static final Logger logger = LoggerFactory.getLogger(FileIndexServiceImpl.class);
    @Resource
    FileIndexMapper fileIndexMapper;

    @Resource
    EmrTemplateMapper emrTemplateMapper;

    @Resource
    EmrCatelogMapper emrCatelogMapper;

    @Resource
    FileIndexEntityMapper fileIndexEntityMapper;

    @Resource
    NurseStatisticsMapper nurseStatisticsMapper;

    @Resource
    FileIndexDataMapper fileIndexDataMapper;

    @Resource
    FilePrintContentMapper filePrintContentMapper;

    @Resource
    FileIndexDataEntityMapper fileIndexDataEntityMapper;

    @Resource
    FileIndexDataElementMapper fileIndexDataElementMapper;

    @Resource
    private SqlSessionFactory sqlSessionFactory;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private TplDetailMapper tplDetailMapper;

    @Resource
    private EmrNurseStatisticsService emrNurseStatisticsService;

    @Autowired
    RuleService ruleService;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private NurseOrdersMapper nurseOrdersMapper;

    @Value("${spring.profiles.active}")
    private String activeProfile;

    private static List<String> signElements;

    private ExecutorService fixedThreadPool;

    private final static String PARAM = "%\"listWarn\":\"1\"%";

    public FileIndexServiceImpl() {
        fixedThreadPool = Executors.newFixedThreadPool(10);
    }

    @Override
    public Result createFileIndex(String tplId, String inpatNum, String deptId, String reqNum, String serialNo) {
        Map<String, String> patientInfo = fileIndexMapper.getPatientInfo(inpatNum);
        if (patientInfo == null) {
            return ResultGenerator.genFailedResult("住院号不存在，无法创建病历。");
        }
        EmrFile emrFile = new EmrFile();
        EmrTemplateEntity tpl = emrTemplateMapper.selectByPrimaryKey(tplId);
        if (tpl == null) {
            return ResultGenerator.genFailedResult("病历模板不存在，无法创建病历。");
        }
        EmrFileIndexEntity emrFileIndex = new EmrFileIndexEntity();
        emrFileIndex.setDataVersion(0);
        emrFileIndex.setFileVersion("2.1");
        Map<String, String> currentUser = getCurrentUser();
        String userName = currentUser.get("userName");
        if (!StringUtils.hasLength(userName)) {
            userName = "无名";
        }
        emrFile.setUserName(userName);
        String groupName = currentUser.get("groupName");
        emrFile.setGroupName(groupName);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH");
        String emrFileName = tpl.getTplName() + "—" + userName + "—" + sdf.format(new Date(System.currentTimeMillis()));
        emrFileIndex.setEmrFileName(emrFileName);
        emrFileIndex.setHospitalId(tpl.getHospitalId());
        emrFileIndex.setEmrFileCode("0");
        emrFileIndex.setOutpatNum("0");
        emrFileIndex.setInpatNum(inpatNum);
        emrFileIndex.setDoctorId(currentUser.get("userId"));
        emrFileIndex.setDeptId(deptId);
        emrFileIndex.setPatientIdcard(patientInfo.get("idNum"));
        EmrCatalogEntity catalog = emrCatelogMapper.selectByPrimaryKey(tpl.getCtlId());
        if (StringUtils.hasLength(catalog.getCtlType())) {
            emrFileIndex.setTplClassId(catalog.getCtlType());
        } else {
            emrFileIndex.setTplClassId("0");
        }
        emrFile.setEmrType(catalog.getEmrType());
        emrFile.setPrintType(catalog.getPrintType());
        emrFileIndex.setDelFlag(FileIndexService.NOT_DELETE);
        emrFileIndex.setFileContentId("0");
        emrFileIndex.setLockFlag("0");
        emrFileIndex.setTplId(tpl.getTplId());
        emrFileIndex.setStatus(FileIndexService.FILE_STATUS_INIT);
        if (FileIndexService.RECORD_TYPE.equals(catalog.getRecordTypes())) { // 首程标志
            emrFileIndex.setDurDisFlag(IS_DUR_DIS);
        } else {
            emrFileIndex.setDurDisFlag(NOT_DUR_DIS); // 非首程标志
        }
        //住院病人床号不为0，取当前床号
        if (!FileIndexEnum.FILE_INDEX_BED_NO_ZERO.getIndex().equals(patientInfo.get("bedNo"))) {
            emrFileIndex.setBedNo(patientInfo.get("bedNo"));
        } else {
            //取最近一条转出记录
            String latestTransferBedNo = fileIndexMapper.getLatestTransferBedNo(inpatNum);
            if (StringUtils.hasLength(latestTransferBedNo)) {
                emrFileIndex.setBedNo(latestTransferBedNo);
            } else {
                //未进行转床或转科，取当前病人最近一份病历中的床号；
                String latestFileIndexBedNo = fileIndexMapper.getLatestFileIndexBedNo(inpatNum);
                if (StringUtils.hasLength(latestFileIndexBedNo)) {
                    emrFileIndex.setBedNo(latestFileIndexBedNo);
                } else {
                    //未进行病历书写,默认为0，支持手动更改床号。
                    emrFileIndex.setBedNo(StringUtils.hasLength(emrFileIndex.getBedNo()) ? emrFileIndex.getBedNo() : FileIndexEnum.FILE_INDEX_BED_NO_ZERO.getIndex());
                }
            }
        }
        if (ONLY_ONE.equals(catalog.getCreateMode())) { // 需要检查病历的唯一性
            int cnt = fileIndexMapper.getFileCnt(inpatNum, catalog.getCtlId());
            if (cnt > 0) {
                return ResultGenerator.genFailedResult("同样的病历已经存在，不能再次创建新病历。");
            }
        }
        // 查询首程是否存在
        Condition condition = new Condition(EmrFileIndexEntity.class);
        condition.createCriteria().andEqualTo("inpatNum", emrFileIndex.getInpatNum())
                .andEqualTo("durDisFlag", IS_DUR_DIS)
                .andNotEqualTo("status", FILE_STATUS_DELETE);
        List<EmrFileIndexEntity> ddFilelist = fileIndexMapper.selectByCondition(condition);
        // 非首程病历需要检查首程是否存在 但是知情同意书除外
        if ("0".equals(catalog.getFirstFlag())) {
            if (NOT_DUR_DIS.equals(emrFileIndex.getDurDisFlag()) && ddFilelist.isEmpty()) {
                return ResultGenerator.genFailedResult("还没有首次病程。");
            }
            // 首程已存在，不能再生成首程
            if (IS_DUR_DIS.equals(emrFileIndex.getDurDisFlag()) && !ddFilelist.isEmpty()) {
                return ResultGenerator.genFailedResult("首次病程已经存在。");
            }
            if (NOT_DUR_DIS.equals(emrFileIndex.getDurDisFlag()) && !ddFilelist.isEmpty()) {
                emrFileIndex.setDdEmrFileId(ddFilelist.get(0).getEmrFileId());
                emrFileIndex.setDdDate(ddFilelist.get(0).getGmtCreate());
            }
            if (IS_DUR_DIS.equals(emrFileIndex.getDurDisFlag())) {
                emrFileIndex.setDdEmrFileId(emrFileIndex.getEmrFileId());
                emrFileIndex.setDdDate(new Timestamp(System.currentTimeMillis()));
            }
        }
        emrFile.setEmrFileIndexEntityOld(emrFileIndex);

        List<CompletableFuture<Tuple2<String, JSONObject>>> datasetFutures = getDatasetMap(tpl.getTplId(), inpatNum, reqNum, serialNo, catalog.getEmrType());

        List<Map<String, String>> observations = fileIndexMapper.queryAllObservations(emrFileIndex.getInpatNum(), tplId);
        emrFile.setObservations(observations);

        List<EmrFileData> dataList = createEmrFileData(emrFileIndex, datasetFutures, patientInfo, catalog);
        dataList.stream().filter(data -> FileIndexService.WENJIANTAITOU_RQSJ.equals(data.getElement().getVarCode())).forEach(data -> {
            data.getFileIndexDataEntity().setDataValue(new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date(System.currentTimeMillis())));
        });
        List<EmrFileData> topList = buildTreeData(dataList, "");
        emrFile.setEmrFileDataList(topList);
        Map attributes = new HashMap();
        attributes.put("ctlName", catalog.getCtlName());
        attributes.put("emrType", catalog.getEmrType());
        emrFile.setAttributes(attributes);
        return ResultGenerator.genOkResult(emrFile);
    }


    /**
     * 获取模板中引用的数据集数据
     *
     * @param tplId 模板ID
     * @param inpatNum  住院号
     * @param reqNum    电子申请单编号
     * @param serialNo  序列号
     * @param emrType   病历类型
     * @return
     */
    private List<CompletableFuture<Tuple2<String, JSONObject>>> getDatasetMap(String tplId, String inpatNum, String reqNum, String serialNo, String emrType) {
        List<Map<String, String>> datasetList = fileIndexMapper.getDatasetListNew(tplId);
        List<CompletableFuture<Tuple2<String, JSONObject>>> futures = datasetList.stream().map(dataset -> {
            return CompletableFuture.supplyAsync(() -> {
                long t1 = System.currentTimeMillis();
                String datasetId = dataset.get("DATASET_ID");
                String url = dataset.get("READ_SERVICE");
                if (!StringUtils.hasLength(url)) {
                    return null;
                }
                HttpHeaders headers = new HttpHeaders();
                headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
                headers.add("api-version", "2.1");
                HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
                Map<String, String> params = new HashMap<String, String>();
                params.put("inpatNum", inpatNum);
                if (StringUtils.hasLength(reqNum)) {
                    params.put("reqNum", reqNum);
                }
                if (StringUtils.hasLength(serialNo)) {
                    params.put("serialNo", serialNo);
                }
                params.put("emrType", emrType);
                HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
                factory.setConnectionRequestTimeout(3000);
                factory.setConnectTimeout(5000);
                RestTemplate restTemplate = new RestTemplate(factory);
                ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class, params);
                JSONObject result = JSONObject.parseObject(response.getBody());
                long t2 = System.currentTimeMillis();
                logger.info("查询第三方接口 {} 数据耗时：{} ms", url, t2 - t1);
                if (result.getInteger("code") == 200) {
                    return Tuples.of(datasetId, result.getJSONObject("data"));
                } else {
                    return null;
                }
            });
        }).collect(Collectors.toList());
        return futures;
    }

    @Override
    @Transactional
    public Result saveFileIndex(EmrFile emrFile) {
        try {
            EmrFileIndexEntity emrFileIndex = emrFile.getEmrFileIndexEntityOld();
            if (FILE_STATUS_DELETE.equals(emrFileIndex.getStatus())) {
                return ResultGenerator.genFailedResult("病历已被删除，无法保存。");
            }
            emrFileIndex.setDataVersion(emrFileIndex.getDataVersion() + 1);
            Timestamp currentTime = new Timestamp(System.currentTimeMillis());
            String inpatNum = emrFileIndex.getInpatNum();
            List<EmrFileData> dataList = flatConvert(emrFile.getEmrFileDataList());
            // 确定文件名和日期 时间戳
            String emrFileName = dataList.stream().filter(data -> WENJIANTAITOU.equals(data.getElement().getVarCode()))
                    .flatMap(data -> data.getEmrFileDataList().stream()).filter(data -> !WENJIANTAITOU_RQSJ.equals(data.getElement().getVarCode()))
                    .map(data -> data.getFileIndexDataEntity().getDataValue()).collect(Collectors.joining(""));
            String fileDatetime = dataList.stream().filter(data -> WENJIANTAITOU.equals(data.getElement().getVarCode()))
                    .flatMap(data -> data.getEmrFileDataList().stream()).filter(data -> WENJIANTAITOU_RQSJ.equals(data.getElement().getVarCode()))
                    .map(data -> data.getFileIndexDataEntity().getDataValue()).collect(Collectors.joining(""));

            Map<String, String> currentUser = getCurrentUser();
            String userName = currentUser.get("userName");
            if (StringUtils.hasLength(emrFileIndex.getEmrFileId())) {//更新时不需要修改创建者姓名
                Map<String, String> createUser = fileIndexMapper.getUser(emrFileIndex.getDoctorId());
                userName = createUser.get("userName");
            }
            if (!StringUtils.hasLength(userName)) {
                userName = "无名";
            }

            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            try {
                if (StringUtils.hasLength(fileDatetime)) {
                    Timestamp ts = new Timestamp(sdf2.parse(fileDatetime).getTime());
                    emrFileIndex.setFileDatetime(ts);
                } else if (emrFileIndex.getFileDatetime() == null) {
                    emrFileIndex.setFileDatetime(new Timestamp(System.currentTimeMillis()));
                }
            } catch (Exception e) {
                logger.error("抬头日期时间转换出错", e);
                return ResultGenerator.genFailedResult("文件日期时间格式不正确。");
            }
            if (StringUtils.hasLength(emrFileName)) {
                SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMddHH");
                emrFileIndex.setEmrFileName(emrFileName + "—" + userName + "—" + sdf1.format(emrFileIndex.getGmtCreate()));
            }

            if (!StringUtils.hasLength(emrFileIndex.getEmrFileId())) {//新建
                emrFileIndex.setEmrFileId(UUIDUtil.randomString());
                emrFileIndex.setGmtCreate(currentTime);
                emrFileIndex.setGmtModify(currentTime);
                emrFileIndex.setLockDoctorId("0");
                emrFileIndex.setLockDate(currentTime);
                emrFileIndex.setCommitDate(currentTime);
                emrFileIndex.setCommitDoctorId("0");

                EmrTemplateEntity tpl = emrTemplateMapper.selectByPrimaryKey(emrFileIndex.getTplId());
                if (tpl == null) {
                    throw new ServiceException("模板已不存在，无法保存。");
                }
                EmrCatalogEntity catalog = emrCatelogMapper.selectByPrimaryKey(tpl.getCtlId());
                if (catalog == null) {
                    throw new ServiceException("病历目录已不存在，无法保存。");
                }

                if (ONLY_ONE.equals(catalog.getCreateMode())) { // 需要检查病历的唯一性
                    int cnt = fileIndexMapper.getFileCnt(emrFileIndex.getInpatNum(), catalog.getCtlId());
                    if (cnt > 0) {
                        throw new ServiceException("同样的病历已经存在，不能再次创建新病历。");
                    }
                }
                Condition condition = new Condition(EmrFileIndexEntity.class);
                condition.createCriteria().andEqualTo("inpatNum", emrFileIndex.getInpatNum())
                        .andEqualTo("durDisFlag", "1")
                        .andNotEqualTo("emrFileId", emrFileIndex.getEmrFileId()).andNotEqualTo("status", "6");
                List<EmrFileIndexEntity> ddFilelist = fileIndexMapper.selectByCondition(condition);
                // 非首程病历需要检查首程是否存在 但是知情同意书除外
                if ("0".equals(catalog.getFirstFlag())) {
//                    if (NOT_DUR_DIS.equals(emrFileIndex.getDurDisFlag()) && ddFilelist.isEmpty()) {
//                        throw new ServiceException("还没有首次病程。");
//                    }
//                    // 首程已存在，不能再生成首程
//                    if (!NOT_DUR_DIS.equals(emrFileIndex.getDurDisFlag()) && !ddFilelist.isEmpty()) {
//                        throw new ServiceException("首次病程已经存在。");
//                    }
                    if (NOT_DUR_DIS.equals(emrFileIndex.getDurDisFlag()) && !ddFilelist.isEmpty()) {
                        emrFileIndex.setDdEmrFileId(ddFilelist.get(0).getEmrFileId());
                        emrFileIndex.setDdDate(ddFilelist.get(0).getGmtCreate());
                    }
                    if (!NOT_DUR_DIS.equals(emrFileIndex.getDurDisFlag())) {
                        emrFileIndex.setDdEmrFileId(emrFileIndex.getEmrFileId());
                        emrFileIndex.setDdDate(new Timestamp(System.currentTimeMillis()));
                    }
                } else {
                    emrFileIndex.setDdEmrFileId("0");
                    emrFileIndex.setDdDate(new Timestamp(System.currentTimeMillis()));
                }
                emrFileIndex.setAuditDate1(currentTime);
                emrFileIndex.setAuditDate2(currentTime);
                emrFileIndex.setAuditDoctorId1("0");
                emrFileIndex.setAuditDoctorId2("0");
                fileIndexEntityMapper.insertSelective(emrFileIndex);
                if (EMR_TYPE_SHOUSHUJILU.equals(emrFile.getEmrType()) || EMR_TYPE_SHUQIANXIAOJIE.equals(emrFile.getEmrType())) {
                    if (org.apache.commons.lang3.StringUtils.isNotBlank(emrFile.getReqNum())) {
                        String type = EMR_TYPE_SHOUSHUJILU.equals(emrFile.getEmrType()) ? "3" : "2";
                        fileIndexEntityMapper.insertCriticalRecord(type, emrFileIndex.getEmrFileId(), emrFile.getReqNum());
                    }
                }

            } else {//更新
                String archiveFlag = fileIndexMapper.getArchiveFlag(emrFileIndex.getInpatNum());
                if (PATIENT_FLAG_ARCHIVE.equals(archiveFlag)) {
                    throw new ServiceException("此病人状态已归档，无法修改。");
                }
//                String userId = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
//                        .getHeader("zuul_id");
//                if (!emrFileIndex.getDoctorId().equals(userId)) { // 非本人需要验证等级
//                    int userPostLevel = fileIndexMapper.getPositionLevel(userId);
//                    int doctorPostLevel = fileIndexMapper.getPositionLevel(emrFileIndex.getDoctorId());
//                    if (userPostLevel < doctorPostLevel) {
//                        throw new ServiceException("您的职务不高于创建者，因此无法保存。");
//                    } else if (userPostLevel == doctorPostLevel) {
//                        int userLevel = fileIndexMapper.queryLevel(userId);
//                        int doctorLevel = fileIndexMapper.queryLevel(emrFileIndex.getDoctorId());
//                        if (userLevel <= doctorLevel) {
//                            throw new ServiceException("您的职称不高于创建者职称，因此无法保存。");
//                        }
//                    }
//                }
                emrFileIndex.setGmtModify(currentTime);
                fileIndexEntityMapper.updateByPrimaryKeySelective(emrFileIndex);
//                //删除打印表中内容
//                FilePrintContentEntity printContentEntity = new FilePrintContentEntity();
//                printContentEntity.setEmrFileId(emrFileIndex.getEmrFileId());
//                filePrintContentMapper.delete(printContentEntity);
            }
            if (emrFileIndex.getDataVersion() > 1) {
                long t1 = System.currentTimeMillis();
                fileIndexMapper.recordBeforeUpdate(emrFileIndex.getEmrFileId());
                long t2 = System.currentTimeMillis();
                logger.info("{} 记录耗时：{} ms", emrFileIndex.getEmrFileId(), t2 - t1);
            }


            //获取表头时间，用来判定是否存在受影响的统计记录
            SimpleDateFormat nodesdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            Date nodeTime = nodesdf.parse(fileDatetime);
            //将受影响的统计记录中的（statisticsId，statisticsType，endTime）字段保存下来，在病历明细表中插入数据后插入统计数据时使用
            emrNurseStatisticsService.delBeforeInsert(emrFile.getEmrFileIndexEntityOld().getInpatNum(),nodeTime);
            long t1 = System.currentTimeMillis();
            SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
            Map<String, Object> params = new HashMap<>();
            params.put("fileIndex", emrFileIndex);
            dataList.stream().map(data -> data.getFileIndexDataEntity()).forEach(dataEntity -> {
                params.put("dataEntity", dataEntity);
                if (dataEntity.getDataValue() == null || dataEntity.getDataValue().length() < 1000) {
                    session.insert("com.haoze.nurse.dao.FileIndexDataEntityMapper.insertDataListWithInlineClob", params);
                } else {
                    session.insert("com.haoze.nurse.dao.FileIndexDataEntityMapper.insertDataListWithIndependentClob", params);
                }
            });
            session.flushStatements();
            session.close();
            //获取刚插入的病历明细的明细表ID，作为统计表的关联字段
            //这个list存的是file_index_data中和出入量相关的纪录
            List<String> fileIndexDataIdList = fileIndexDataMapper.queryAllFileIndexData(emrFile.getEmrFileIndexEntityOld().getEmrFileId());
            for(int i = 0;i < fileIndexDataIdList.size();i++){
                emrNurseStatisticsService.addAllstatistics(emrFile.getEmrFileIndexEntityOld().getInpatNum(), emrFile.getEmrFileIndexEntityOld().getTplId(),nodeTime,fileIndexDataIdList.get(i));
            }

            fileIndexDataEntityMapper.removeDeletedNodes(emrFileIndex.getEmrFileId(), emrFileIndex.getDataVersion());
            long t2 = System.currentTimeMillis();
            logger.info("{} 明细存储耗时：{} ms", emrFileIndex.getEmrFileId(), t2 - t1);

            if (emrFileIndex.getDataVersion() > 1) {
                t1 = System.currentTimeMillis();
                fileIndexMapper.compareAfterUpdate(emrFileIndex.getEmrFileId(), UUIDUtil.randomString(), currentUser.get("userId"));
                t2 = System.currentTimeMillis();
                logger.info("{} 比较耗时：{} ms", emrFileIndex.getEmrFileId(), t2 - t1);
                List<Map<String, Object>> invalidDeletedElements = fileIndexMapper.getInvalidDeletedElements(emrFileIndex.getEmrFileId());
                if (invalidDeletedElements.size() > 0) {
                    logger.error("非法操作 删除数据：{}", JSON.toJSONString(invalidDeletedElements));
                }
            }

            // 立即缓存！ 后续操作可能修改emrFile中的节点
            // 评估类病历不缓存
//            if (!PROFILE_DEV.equals(activeProfile) && !emrFile.getEmrType().startsWith("REVIEW")) {
//                try {
//                    redisUtil.set(emrFileIndex.getEmrFileId(), emrFile);
//                } catch (Exception e) {
//                    logger.error("缓存保存时出错。", e);
//                }
//            }

//            // 查找符合条件的诊断项目
//            dataList.stream().filter(data -> isDiag(data.getElement().getVarCode())).findFirst().ifPresent(diagData -> {
//                if (emrFile.getCorrectModified() && FileIndexService.NOT_DUR_DIS.equals(emrFileIndex.getDurDisFlag())) {
//                    updateCorrectDiag(diagData, emrFileIndex, emrFile.getCorrectUsername(), emrFile.getCorrectUserpwd());
//                }
//                String mainDiagId = fileIndexMapper.getLatestMainDiag(emrFileIndex.getInpatNum());
//                if (StringUtils.hasLength(mainDiagId)) {
//                    fileIndexMapper.updateMainDiag(inpatNum, mainDiagId);
//                }
//            });
//            if (dataList.stream().anyMatch(data -> FileIndexService.CK_RSFXDJ.equals(data.getElement().getVarCode()))) {
//                fixedThreadPool.execute(() -> {
//                    updatePregnancyDangerLevel(emrFileIndex);
//                });
//            }
//
//            // 危急值处理
//            if (EMR_TYPE_WEIJIZHICHULI.equals(emrFile.getEmrType()) && StringUtils.hasLength(emrFile.getItemIds())) {
//                fixedThreadPool.execute(() -> {
//                    fileIndexMapper.stopCritical(emrFile.getItemIds().split(","));
//                });
//            }
//            //出院记录（顺产） / 剖宫产出院 推送孕妇分娩信息
//            if (EMR_TYPE_CHUYUANJILU.equals(emrFile.getEmrType())) {
//                fixedThreadPool.execute(() -> {
//                    pushToSystem(emrFileIndex.getEmrFileId());
//                });
//            }
            //刷新质控提醒
//            fixedThreadPool.execute(() -> {
//                ruleService.refreshRemindInformation(inpatNum, emrFileIndex.getTplId());
//            });

        } catch (ServiceException e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResultGenerator.genFailedResult(e.getMessage());
        } catch (Exception e) {
            logger.error("保存病历出错。", e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResultGenerator.genFailedResult(e.getMessage());
        }

        return ResultGenerator.genOkResult(emrFile.getEmrFileIndexEntityOld().getEmrFileId());
    }

    @Override
    public EmrFile getFileIndex(String emrFileId,String showINOUT) {
        EmrFileIndexEntity emrFileIndex = fileIndexEntityMapper.selectByPrimaryKey(emrFileId);
        if (emrFileIndex == null) {
            return null;
        }
        EmrFile emrFile = getDataFromDB(emrFileIndex,showINOUT);
//        if (!PROFILE_DEV.equals(activeProfile) && redisUtil.hasKey(emrFileId)) {
//            emrFile = (EmrFile) redisUtil.get(emrFileId);
//            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//            String cacheTime = sdf.format(emrFile.getEmrFileIndexEntity().getGmtModify());
//            String dbTime = sdf.format(emrFileIndex.getGmtModify());
//            if (!cacheTime.equals(dbTime)) {
//                logger.info("{} 缓存的时间戳（{}）和数据库的时间戳（{}）不一致，不使用缓存。", emrFileId, cacheTime, dbTime);
//                emrFile = getDataFromDB(emrFileIndex);
//            } else {
//                updateElement(emrFile);
//            }
//        } else {
//            emrFile = getDataFromDB(emrFileIndex);
//        }
        return emrFile;
    }

    @Override
    public Result deleteFileIndex(String emrFileId) {
        EmrFileIndexEntity emrFileIndex = fileIndexEntityMapper.selectByPrimaryKey(emrFileId);
//        String archiveFlag = fileIndexMapper.getArchiveFlag(emrFileIndex.getInpatNum());
//        if (StringUtils.hasLength(archiveFlag)) {
//            return ResultGenerator.genFailedResult("病人已出院，无法删除病历。");
//        }
        String userId = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
                .getHeader("zuul_id");
//        if (!FILE_STATUS_INIT.equals(emrFileIndex.getStatus())) {
//            int userPostLevel = fileIndexMapper.getPositionLevel(userId);
//            if (userPostLevel < 9) {//科主任可以删除病历
//                return ResultGenerator.genFailedResult("病历状态已改变，无法删除。");
//            }
//        } else {
//            if (!emrFileIndex.getDoctorId().equals(userId)) { // 只有本人可以删除自己的病历
//                return ResultGenerator.genFailedResult("只有创建者可以删除自己的病历。");
//            }
//        }

        emrFileIndex.setStatus(FILE_STATUS_DELETE);
        emrFileIndex.setDeleteUserId(userId);
        fileIndexEntityMapper.updateByPrimaryKey(emrFileIndex);
//        //删除病历时，包含妊娠风险等级的话取最新的update
//        String level = fileIndexDataEntityMapper.getLevel(emrFileIndex.getEmrFileId());
//        if (StringUtils.hasLength(level)) {
//            String healthNum = fileIndexDataEntityMapper.getHealthNumByInpatNum(emrFileIndex.getInpatNum());
//            fileIndexDataEntityMapper.updateLastPatientLevel(healthNum);
//        }
        if (!PROFILE_DEV.equals(activeProfile) && redisUtil.hasKey(emrFileId)) {
            redisUtil.remove(emrFileId);
        }
        fileIndexEntityMapper.deleteCriticalRecord(emrFileIndex.getEmrFileId());
        fileIndexEntityMapper.deleteDetail(emrFileIndex.getEmrFileId());
        //刷新质控提醒列表
//        fixedThreadPool.execute(() -> {
//            ruleService.refreshRemindInformation(emrFileIndex.getInpatNum(),emrFileIndex.getTplId());
//        });
        //出入量总结因对应关系有单独的删除方式
        //用emrFileId获取病历信息，获取病历中的tpl_id用来判断为出入量总结或8种其他统计类型
        if(emrFileIndex.getTplId().equals(fileIndexDataElementMapper.getElementIdByvarCode("crlzjmb"))){
            delInOutSummary(emrFileId);
        }else {
            //添加判断，8种统计类型，按如下方式删除
            List<Map<String, String>> array = emrNurseStatisticsService.delBeforeInsert(emrFileIndex.getInpatNum(), emrFileIndex.getFileDatetime());
            List<String> list = fileIndexDataMapper.queryAllFileIndexData(emrFileId);
            for (int i = 0; i < list.size(); i++) {
                deleteStatisticsByFileIndexId(list.get(i));
                emrNurseStatisticsService.updateAllStatistics(array, emrFileIndex.getInpatNum(), emrFileIndex.getFileDatetime(), list.get(i));
            }
        }
        return ResultGenerator.genOkResult();
    }

    private void deleteStatisticsByFileIndexId(String fileIndexDataId) {
        List<String> list = nurseStatisticsMapper.queryIdByFileIndexDataId(fileIndexDataId);
        for (int i = 0;i < list.size();i++){
            nurseStatisticsMapper.deleteStatistics(list.get(i));
        }
    }

    private void delInOutSummary(String emrFileId){
        List<String> list = nurseStatisticsMapper.queryIdByFileIndexDataId(emrFileId);
        for (int i = 0;i < list.size();i++){
            nurseStatisticsMapper.deleteStatistics(list.get(i));
        }
    }

    @Override
    public Result recoveryFileIndex(String emrFileId) {
        EmrFileIndexEntity emrFileIndex = fileIndexEntityMapper.selectByPrimaryKey(emrFileId);
        if (!FILE_STATUS_DELETE.equals(emrFileIndex.getStatus())) {
            return ResultGenerator.genFailedResult("病历未被删除，无需恢复。");
        }
        String userId = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
                .getHeader("zuul_id");
        if (!emrFileIndex.getDoctorId().equals(userId)) {
            return ResultGenerator.genFailedResult("只有病历的创建者才能恢复此病历。");
        }
        EmrTemplateEntity tpl = emrTemplateMapper.selectByPrimaryKey(emrFileIndex.getTplId());
        EmrCatalogEntity catalog = emrCatelogMapper.selectByPrimaryKey(tpl.getCtlId());
        if (ONLY_ONE.equals(catalog.getCreateMode())) {
            List<EmrFileIndexEntity> filelist = fileIndexEntityMapper.queryExistFile(catalog.getCtlId(), emrFileIndex.getInpatNum());
            if (!filelist.isEmpty()) {
                return ResultGenerator.genFailedResult("同样的病历已经存在，不能恢复此病历。");
            }
        }
        String archiveFlag = fileIndexMapper.getArchiveFlag(emrFileIndex.getInpatNum());
        if (StringUtils.hasLength(archiveFlag)) { // 病人已出院 提交状态
            emrFileIndex.setStatus(FILE_STATUS_COMMIT);
        } else { // 未出院 保存状态
            emrFileIndex.setStatus(FILE_STATUS_INIT);
        }

        fileIndexEntityMapper.updateByPrimaryKey(emrFileIndex);
        fileIndexEntityMapper.recoveryDetail(emrFileIndex.getEmrFileId());

        return ResultGenerator.genOkResult();
    }

    @Override
    public Result getChanges(String emrFileId) {
        List<FileIndexDataDetailVO> detailList = fileIndexMapper.queryDetail(emrFileId);
        detailList.parallelStream().forEach(detail -> {
            detail.setPath(fileIndexMapper.getPath(detail.getParentFileIndexDataId(), emrFileId));
        });
        return ResultGenerator.genOkResult(detailList);
    }



    public Map<String, String> getCurrentUser() {
        String userId = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()
                .getHeader("zuul_id");
        Map<String, String> currentUser = fileIndexMapper.getUser(userId);
        if (currentUser == null)
            return new HashMap<String, String>();
        return currentUser;
    }

    private List<EmrFileData> createEmrFileData(EmrFileIndexEntity emrFileIndex,
                                                List<CompletableFuture<Tuple2<String, JSONObject>>> datasetFeatures,
                                                Map<String, String> patientInfo, EmrCatalogEntity catalog) {
        long t1 = System.currentTimeMillis();
        List<Map<String, Object>> list = fileIndexMapper.createEmrFileData(emrFileIndex);
        long t2 = System.currentTimeMillis();
        logger.info("{} 模板{}条查询时间：{} ms", emrFileIndex.getTplId(), list.size(), t2 - t1);
        List<EmrFileData> emrFileDataList = convertData(list);
        Map<String, Map<String, Object>> datasetMap = new HashMap<>();
        try {
            CompletableFuture.allOf(datasetFeatures.toArray(new CompletableFuture[datasetFeatures.size()])).thenApply(v -> {
                return datasetFeatures.stream().map(datasetFeature -> datasetFeature.join())
                        .collect(Collectors.toList());
            }).get().stream().filter(tuple2 -> tuple2 != null).forEach(tuple2 -> {
                datasetMap.put(tuple2.getT1(), tuple2.getT2());
            });
        } catch (Exception e) {
            logger.error("查询第三方接口出现错误。", e);
        }
        int orignialSize = emrFileDataList.size();
        for (int i = 0; i < orignialSize; i++) {
            EmrFileData emrFileData = emrFileDataList.get(i);
            FileIndexDataEntity dataEntity = emrFileData.getFileIndexDataEntity();
            String oldId = dataEntity.getFileIndexDataId();
            String newId = UUIDUtil.randomString();
            dataEntity.setFileIndexDataId(newId);
            Element element = emrFileData.getElement();

            // 引用数据集
            if (StringUtils.hasLength(dataEntity.getQuoteDatasetId()) && StringUtils.hasLength(dataEntity.getQuoteElementId())) {
                updateQuoteDatasetValue(datasetMap, emrFileData, true);
            }
            // 补充全部勾选项
            if (element.getElementPropertyFormat() != null && element.getElementPropertyFormat().indexOf("\"formatValue\":\"2\"") > -1) {
                element.setSelections(fileIndexMapper.getAllSelections(element.getId()));
            }

            // 引用其他病历 新版本
            if (StringUtils.hasLength(dataEntity.getQuoteTplDetailId()) && dataEntity.getQuoteTplDetailId().startsWith("[[")) {
                JSONArray priorityArray = JSONArray.parseArray(dataEntity.getQuoteTplDetailId());
                for (Object priorityObj : priorityArray) {
                    JSONArray totalArray = (JSONArray) priorityObj;
                    boolean isFound = totalArray.stream().map(parallelingObj -> {
                        JSONObject quoteRule = (JSONObject) parallelingObj;
                        String emrType = quoteRule.getString("emrType");
                        if (StringUtils.isEmpty(emrType)) {
                            logger.info("缺少目录类型，无法引用。");
                            return false;
                        }
                        List<FileIndexDataEntity> refDataList = fileIndexMapper.queryRefData(quoteRule.getString("quoteId"), emrType, emrFileIndex.getInpatNum(), quoteRule.getString("quoteAll"));
                        if (refDataList.isEmpty()) { // 引用节点已不存在 忽略
                            return false;
                        }
                        return IntStream.range(0, refDataList.size()).mapToObj(idx -> {
                            FileIndexDataEntity refData = refDataList.get(idx);
                            if ("Y".equals(quoteRule.getString("oneToOne"))) { // 点对点引用
                                if (StringUtils.isEmpty(refData.getDataValue())) {
                                    return false;
                                }
                                dataEntity.setDataValue(refData.getDataValue());
                                dataEntity.setDataCode(refData.getDataCode());
                                return true; // 有数据 才算找到
                            }
                            // 引用下级节点
                            long t3 = System.currentTimeMillis();
                            List<EmrFileData> refList = getEmrFileData(refData.getEmrFileId(), refData.getFileIndexDataId(),NurseEnum.SHOW_INOUT_NO.getIndex());
                            long t4 = System.currentTimeMillis();
                            logger.info("被引用病历{}条查询时间：{} ms", refList.size(), t4 - t3);
                            if (refList.isEmpty()) { // 无子节点 也算找到了
                                return true;
                            }
                            String type = quoteRule.getString("type");
                            if ("2".equals(type)) { // 医疗术语 引用节点本身也添加进去
                                EmrFileData tempData = new EmrFileData();
                                Element tempElement = new Element();
                                tempElement.setType("20");
                                tempData.setElement(tempElement);
                                tempData.setFileIndexDataEntity(refData);
                                refList.add(0, tempData);
                            }
                            for (int j = 0; j < refList.size(); j++) {
                                EmrFileData subRefData = refList.get(j);
                                subRefData.setFirstQuote(true); // 标记为第一次引用 提示前端不要进行自引用修改
                                FileIndexDataEntity refDataEntity = subRefData.getFileIndexDataEntity();
                                if ("2".equals(type)) {
                                    if (refDataEntity == refData) { // 医疗术语本身
                                        refDataEntity.setParentFileIndexDataId(newId);
                                    }
                                } else {
                                    if (refDataEntity.getParentFileIndexDataId().equals(refData.getFileIndexDataId())) {
                                        refDataEntity.setParentFileIndexDataId(newId);
                                    }
                                }

                                String subOldId = refDataEntity.getFileIndexDataId();
                                String subNewId = UUIDUtil.randomString();
                                refDataEntity.setFileIndexDataId(subNewId);
                                refDataEntity.setGmtCreate(dataEntity.getGmtCreate());
                                refDataEntity.setGmtModify(dataEntity.getGmtModify());
                                try {
                                    String elementProperty = refDataEntity.getElementProperty();
                                    JSONObject jsonObject = JSONObject.parseObject(elementProperty);
                                    jsonObject.put("printNewLine", "1");
                                    jsonObject.put("childPrintNewLine", "1");
                                    jsonObject.put("printAlign", "0");
                                    jsonObject.put("printFontBold", "1");
                                    jsonObject.put("printSplitLine", "1");
                                    jsonObject.put("childrenPrintAlign", "0");
                                    jsonObject.put("selfPrintAlign", "0");
                                    if (idx != 0 && j == 0) { // 第一项增加一个换行符号
                                        jsonObject.put("newLine", "0");
                                        jsonObject.put("printNewLine", "0");
                                    }
                                    refDataEntity.setElementProperty(jsonObject.toJSONString());
                                } catch (Exception e) {
                                    logger.error("重置elementProperty出错。", e);
                                }
                                for (int k = j; k < refList.size(); k++) {
                                    EmrFileData subNextData = refList.get(k);
                                    FileIndexDataEntity subNextDataEntity = subNextData.getFileIndexDataEntity();
                                    if (subOldId.equals(subNextDataEntity.getParentFileIndexDataId())) {
                                        subNextDataEntity.setParentFileIndexDataId(subNewId);
                                    }
                                }
                            }

                            emrFileDataList.addAll(refList);
                            return true;
                        }).reduce(false, (accumulatorBoolean, nextBoolean) -> accumulatorBoolean || nextBoolean);
                    }).reduce(false, (accumulatorBoolean, nextBoolean) -> accumulatorBoolean || nextBoolean);
                    // 如果已经引用到数据 终止循环
                    if (isFound) {
                        break;
                    }
                }
            }
            // 补充父级ID
            for (int j = i + 1; j < orignialSize; j++) {
                EmrFileData nextData = emrFileDataList.get(j);
                if (oldId.equals(nextData.getFileIndexDataEntity().getParentFileIndexDataId())) {
                    nextData.getFileIndexDataEntity().setParentFileIndexDataId(newId);
                }
            }
        }
        Map<String, String> currentUser = getCurrentUser();
        String groupName = currentUser.get("groupName");
        return emrFileDataList.parallelStream().filter(emrFileData -> {
            Element element = emrFileData.getElement();
            if ("wenjiantaitou-rqsj".equals(element.getVarCode())) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
                emrFileData.getFileIndexDataEntity().setDataValue(sdf.format(new Date(System.currentTimeMillis())));
            }
            if ("手术名称".equals(element.getName()) && "手术名称".equals(emrFileData.getFileIndexDataEntity().getDataValue())) {
                emrFileData.getFileIndexDataEntity().setDataValue("-");
            }
            if (EMR_TYPE_SHOUCIBINGCHENG.equals(catalog.getEmrType()) || EMR_TYPE_RUYUANBINGCHENG.equals(catalog.getEmrType())) { // 首次病程和入院病程 入院与初步二选一
                // 医师不能有入院诊断
                if (RUYUANZHENDUAN.equals(element.getVarCode())) {
                    return !"医师".equals(groupName);
                }
                // 非医师不能有初步诊断
                if (CHUBUZHENDUAN.equals(element.getVarCode())) {
                    return "医师".equals(groupName);
                }
            } else { // 其他病程 不保留初步诊断
                if (CHUBUZHENDUAN.equals(element.getVarCode())) {
                    return false;
                }
            }
            // 非医师不能有上级医师签名/时间 (主任查房和上级医师查房和出院记录除外)
            if (
                    (SHANGJIYISHIQIANMING.equals(element.getVarCode()) || SHANGJIYISHIQIANMINGRIQISHIJIAN.equals(element.getVarCode()) || sjysqmzc.equals(element.getVarCode()))
                            && !EMR_TYPE_SHANGJIYISHICHAFANG.equals(catalog.getEmrType())
                            && !EMR_TYPE_ZHURENYISHICHAFANG.equals(catalog.getEmrType())
                            && !EMR_TYPE_CHUYUANJILU.equals(catalog.getEmrType())
                            && !EMR_TYPE_SHSHZCFJL.equals(catalog.getEmrType())
                            && !EMR_TYPE_SHSJYSCFJL.equals(catalog.getEmrType())) {
                return "医师".equals(groupName);
            }
            //医师过滤掉医师签名时间（入院记录上级医师创建时需要显示医师签名时间）
            if (YISHIQIANMINGSHIJIAN.equals(element.getVarCode())) {
                return !"医师".equals(groupName);
            }
            // 判断是患者还是患儿
            int ageYear = Integer.parseInt(patientInfo.get("ageYear"));
            if (HUANZHEHUOHUANER.equals(element.getVarCode())) {
                if (ageYear <= 14) {
                    emrFileData.getFileIndexDataEntity().setDataValue("患儿");
                } else {
                    emrFileData.getFileIndexDataEntity().setDataValue("患者");
                }
            }
            // 判断男性还是女性
            if (HUNYINYUYUEYING.equals(element.getVarCode())) {
                String sex = patientInfo.get("sex");
                if (!FileIndexService.FEMALE.equals(sex)) {
                    //男性
                    if (ageYear > 14) {
                        emrFileData.getFileIndexDataEntity().setDataValue("婚育史");
                    } else {
                        return false;
                    }
                } else {
                    //女性
                    if (ageYear > 14) {
                        emrFileData.getFileIndexDataEntity().setDataValue("婚育史、月经史");
                    } else {
                        return false;
                    }
                }
            }
            //日期类型
            if (FileIndexService.ELEMENT_TYPE_THREE.equals(element.getType())) {
                String time = emrFileData.getFileIndexDataEntity().getDataValue();
                if (StringUtils.hasLength(time)) {
                    Date dateStr = null;
                    String dataValue = time;
                    try {
                        if (StringUtils.hasLength(element.getFormat())) {//redis中未存elementPropertyFormat 直接取format
                            JSONObject format = JSONObject.parseObject(element.getFormat());
                            String formatValue = format.getString("formatValue");
                            if (StringUtils.hasLength(formatValue)) {
                                if ("HH:mm".equals(formatValue)) {
                                    if (time.length() > 11) { //引用其他病历存在 HH:mm 值
                                        dataValue = time.substring(11);
                                    } else {
                                        dataValue = time;
                                    }
                                } else {
                                    SimpleDateFormat sdf = new SimpleDateFormat(formatValue);//格式取数据元定义格式
                                    dateStr = sdf.parse(time);
                                    dataValue = sdf.format(dateStr);
                                }
                            }
                        }
                    } catch (Exception e) {
                        dataValue = time;
                        logger.error("日期数据转换出错。", e);
                    }
                    emrFileData.getFileIndexDataEntity().setDataValue(dataValue);
                }
            }
            return true;
        }).collect(Collectors.toList());
    }

    private void updateQuoteDatasetValue(Map<String, Map<String, Object>> datasetMap, EmrFileData emrFileData, boolean trigger) {
        FileIndexDataEntity dataEntity = emrFileData.getFileIndexDataEntity();
        Element element = emrFileData.getElement();
        Map<String, Object> dataset = datasetMap.get(dataEntity.getQuoteDatasetId());
        if (dataset != null) {
            Object value = dataset.get(dataEntity.getQuoteElementId());
            if (value != null) {
                switch (element.getType()) {
                    case TYPE_SIGNLE_SELECTION:
                    case TYPE_MULTIPLE_SELECTION:
                        try {
                            String[] dataPair = value.toString().split(FileIndexService.SPECIAL_SPLITER);
                            if (dataPair.length == 2) {
                                dataEntity.setDataCode(dataPair[0]);
                                dataEntity.setDataValue(dataPair[1]);
                                emrFileData.setFirstTrigger(trigger);
                            } else {
                                // 麻醉方法代码只能返回文本
                                dataEntity.setDataValue(value.toString().replaceAll("\\$€\\$€\\$", ""));
                            }
                        } catch (Exception e) {
                            logger.error("赋值出错。", e);
                        }
                        break;
                    default:
                        dataEntity.setDataValue(value.toString());
                }
            }
        }
    }

    private List<EmrFileData> convertData(List<Map<String, Object>> list) {
        return list.parallelStream().map(map -> {
            EmrFileData data = new EmrFileData();
            FileIndexDataEntity dataEntity = new FileIndexDataEntity();
            dataEntity.setFileIndexDataId((String) map.get("FILE_INDEX_DATA_ID"));
            try {
                if (map.get("GMT_CREATE") instanceof TIMESTAMP) {
                    dataEntity.setGmtCreate(((TIMESTAMP) map.get("GMT_CREATE")).timestampValue());
                } else {
                    dataEntity.setGmtCreate(((Date) map.get("GMT_CREATE")));
                }
            } catch (SQLException e) {
                logger.error("转换对象出错。", e);
            }
            try {
                if (map.get("GMT_MODIFY") instanceof TIMESTAMP) {
                    dataEntity.setGmtModify(((TIMESTAMP) map.get("GMT_MODIFY")).timestampValue());
                } else {
                    dataEntity.setGmtModify(((Date) map.get("GMT_MODIFY")));
                }
            } catch (SQLException e) {
                logger.error("转换对象出错。", e);
            }
            dataEntity.setSortId(((Number) map.get("SORT_ID")).intValue());
            dataEntity.setDatasetId((String) map.get("DATASET_ID"));
            dataEntity.setElementId((String) map.get("ELEMENT_ID"));
            dataEntity.setParentElementId((String) map.get("PARENT_ELEMENT_ID"));
            dataEntity.setQuoteDatasetId((String) map.get("QUOTE_DATASET_ID"));
            dataEntity.setQuoteElementId((String) map.get("QUOTE_ELEMENT_ID"));
            dataEntity.setDataCode((String) map.get("DATA_CODE"));
            dataEntity.setParentFileIndexDataId((String) map.get("PARENT_FILE_INDEX_DATA_ID"));
            dataEntity.setBaseTplDetailId((String) map.get("BASE_TPL_DETAIL_ID"));
            dataEntity.setQuoteTplDetailId((String) map.get("QUOTE_TPL_DETAIL_ID"));
            String dataValue = "";
            if (map.get("DATA_VALUE_STR") != null) {
                dataValue = (String) map.get("DATA_VALUE_STR");
            } else {
                try {
                    if (map.get("DATA_VALUE") != null) {
                        if (map.get("DATA_VALUE") instanceof Clob) {
                            Clob clob = (Clob) map.get("DATA_VALUE");
                            BufferedReader reader = new BufferedReader(clob.getCharacterStream());
                            dataValue = FileCopyUtils.copyToString(reader);
                        } else {
                            dataValue = (String) map.get("DATA_VALUE");
                        }
                    }
                } catch (SQLException | IOException e) {
                    logger.error("转换对象出错。", e);
                }
            }
            dataEntity.setDataValue(dataValue);
            dataEntity.setPrintIdentification((String) map.get("PRINT_IDENTIFICATION"));
            dataEntity.setShowIdentification((String) map.get("SHOW_IDENTIFICATION"));
            dataEntity.setDeleteIdentification((String) map.get("DELETE_IDENTIFICATION"));
            dataEntity.setElementProperty((String) map.get("ELEMENT_PROPERTY"));
            dataEntity.setGroupNo((String) map.get("GROUP_NO"));
            dataEntity.setMedicalId((String) map.get("MEDICAL_ID"));
            dataEntity.setUnit((String) map.get("UNIT"));
            data.setNeedChanged(map.get("NEED_CHANGED") == null ? "1" : map.get("NEED_CHANGED").toString());
            data.setFileIndexDataEntity(dataEntity);
            data.setTplDetailId((String) map.get("TPL_DETAIL_ID"));
            // 补充权限调用属性
            if (map.get("TPL_DETAIL_ROLE_ID") != null) {
                EmrTemplateDetailRoleEntity roleEntity = new EmrTemplateDetailRoleEntity();
                roleEntity.setEditRoleType((String) map.get("EDIT_ROLE_TYPE"));
                roleEntity.setEditRoleId((String) map.get("EDIT_ROLE_ID"));
                roleEntity.setEditDeptId((String) map.get("EDIT_DEPT_ID"));
                roleEntity.setShowRoleType((String) map.get("SHOW_ROLE_TYPE"));
                roleEntity.setShowRoleId((String) map.get("SHOW_ROLE_ID"));
                roleEntity.setShowDeptId((String) map.get("SHOW_DEPT_ID"));
                roleEntity.setPrintRoleType((String) map.get("PRINT_ROLE_TYPE"));
                roleEntity.setPrintRoleId((String) map.get("PRINT_ROLE_ID"));
                roleEntity.setPrintDeptId((String) map.get("PRINT_DEPT_ID"));
                roleEntity.setRefState((String) map.get("REF_STATE"));
                roleEntity.setRefRoleType((String) map.get("REF_ROLE_TYPE"));
                roleEntity.setRefRoleId((String) map.get("REF_ROLE_ID"));
                roleEntity.setRefDeptId((String) map.get("REF_DEPT_ID"));
                data.setRoleEntity(roleEntity);
            }
            // 补充数据元属性
            Element element = new Element();
            element.setId((String) map.get("ELEMENT_ID"));
            element.setName((String) map.get("ELEMENT_NAME"));
            element.setType((String) map.get("ELEMENT_DATA_TYPE_ID"));
            element.setMin(map.get("MIN_VALUE") == null ? null : ((Number) map.get("MIN_VALUE")).doubleValue());
            element.setMax(map.get("MAX_VALUE") == null ? null : ((Number) map.get("MAX_VALUE")).doubleValue());
            element.setUnit(map.get("ELEMENT_UNIT") == null ? null : map.get("ELEMENT_UNIT").toString());
            element.setVarCode((String) map.get("VAR_CODE"));
            element.setMedicalId(dataEntity.getMedicalId());
            element.setFormat((String) map.get("ELEMENT_PROPERTY_FORMAT"));
            element.setElementPropertyFormat((String) map.get("ELEMENT_PROPERTY_FORMAT"));
            element.setIsPreDiag(map.get("IS_PRE_DIAG") == null ? null : map.get("IS_PRE_DIAG").toString());
            data.setElement(element);

            data.setEmrFileDataList(new ArrayList<>());
            return data;
        }).collect(Collectors.toList());
    }

    /**
     * 构造病历数据树
     *
     * @param list                  病历数据
     * @param parentFileIndexDataId 顶级数据节点ID 可以为null
     * @return
     */
    private List<EmrFileData> buildTreeData(List<EmrFileData> list, String parentFileIndexDataId) {
        List<EmrFileData> topList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            EmrFileData node = list.get(i);
            node.setEmrFileDataList(new ArrayList<>());
            if (node.getFileIndexDataEntity().getParentFileIndexDataId() == null
                    || node.getFileIndexDataEntity().getParentFileIndexDataId().equals(parentFileIndexDataId)) {
                node.setPath("");
                topList.add(node);
                continue;
            }
            for (int j = 0; j < i; j++) {
                EmrFileData parent = list.get(j);
                if (parent.getFileIndexDataEntity().getFileIndexDataId().equals(node.getFileIndexDataEntity().getParentFileIndexDataId())) {
                    node.setPath(parent.getPath() + "," + parent.getFileIndexDataEntity().getFileIndexDataId());
                    parent.getEmrFileDataList().add(node);
                    break;
                }
            }
        }
        return topList;
    }

    /**
     * 查询病历数据列表
     *
     * @param emrFileId             病历ID
     * @param parentFileIndexDataId 父级数据ID 可以为null
     * @return
     */
    private List<EmrFileData> getEmrFileData(String emrFileId, String parentFileIndexDataId,String showINOUT) {
        long t1 = System.currentTimeMillis();
        List<Map<String, Object>> list = fileIndexMapper.getAllFileIndexDataEntity(emrFileId, parentFileIndexDataId,showINOUT);
        long t2 = System.currentTimeMillis();
        logger.info("{} 从数据库获取{}条数据时间： {} ms", emrFileId, list.size(), t2 - t1);
        List<EmrFileData> emrFileDataList = convertData(list);
        emrFileDataList.stream().forEach(emrFileData -> {
            Element element = emrFileData.getElement();
            // 补充全部勾选项
            if (element.getElementPropertyFormat() != null && element.getElementPropertyFormat().indexOf("\"formatValue\":\"2\"") > -1) {
                element.setSelections(fileIndexMapper.getAllSelections(element.getId()));
            }
//            try {
//                String elementProperty = emrFileData.getFileIndexDataEntity().getElementProperty();
//                if (elementProperty.indexOf("\"renderType\":\"sign\"") > -1) { // 签名区域
//                    String groupName = fileIndexMapper.getGroupNameByUserId(emrFileData.getFileIndexDataEntity().getDataCode());
//                    element.setGroupName(groupName == null ? "职称未知" : groupName);
//                }
//            } catch (Exception e) {
//                logger.error("赋值签名职称出错", e);
//            }
        });
        return emrFileDataList;
    }

    /**
     * 保存数据元
     *
     * @param emrFileDataList
     */
    private List<EmrFileData> flatConvert(List<EmrFileData> emrFileDataList) throws Exception {
        Timestamp currentTime = new Timestamp(System.currentTimeMillis());
        Stack<EmrFileData> stack = new Stack<>();
        List<EmrFileData> dataList = new ArrayList<>();
        for (int i = 0; i < emrFileDataList.size(); i++) {
            EmrFileData topEmrFileData = emrFileDataList.get(i);
            topEmrFileData.getFileIndexDataEntity().setParentFileIndexDataId("");
            topEmrFileData.getFileIndexDataEntity().setSortId(i + 1);
            stack.push(topEmrFileData);

            while (!stack.empty()) {
                EmrFileData emrFileData = stack.pop();
                FileIndexDataEntity dataEntity = emrFileData.getFileIndexDataEntity();
                if (dataEntity.getGmtCreate() == null) {
                    dataEntity.setGmtCreate(currentTime);
                    dataEntity.setGmtModify(currentTime);
                } else {
                    dataEntity.setGmtModify(currentTime);
                }
                //判断elementId是否为空，同时校验值域字典
                if (StringUtils.isEmpty(dataEntity.getElementId())) {
                    if (StringUtils.hasLength(dataEntity.getDataValue())) {
                        Element element = emrFileData.getElement();
                        String elementId;
                        if(StringUtils.hasLength(element.getVarCode())){
                            elementId = emrTemplateMapper.getSysElementIdByVarCode(element.getVarCode());
                        }else{
                            elementId = fileIndexMapper.getSysElementId(FileIndexService.MB_WB);
                        }
                        if (StringUtils.isEmpty(elementId)) {
                            throw new ServiceException(dataEntity.getDataValue() + "没有数据元id,无法保存！");
                        } else {
                            dataEntity.setElementId(elementId);
                        }
                    } else {
                        String elementId = fileIndexMapper.getSysElementId(FileIndexService.MB_WB);
                        if (StringUtils.isEmpty(elementId)) {
                            throw new ServiceException(dataEntity.getDataValue() + "没有数据元id,无法保存！");
                        } else {
                            dataEntity.setElementId(elementId);
                        }
                    }
                }
                //签名保存职称
                if (StringUtils.isEmpty(signElements)) {
                    signElements = fileIndexMapper.getSignElementIds();
                }
                if (signElements.contains(dataEntity.getElementId())) {
                    if (StringUtils.hasLength(dataEntity.getDataCode())) {
                        String groupName = fileIndexMapper.getGroupNameByUserId(dataEntity.getDataCode());
                        dataEntity.setExtendedField(groupName == null ? "职称未知" : groupName);
                    }
                }
                // 废弃部分属性 减少缓存时的体积
                emrFileData.setRoleEntity(null);

                dataList.add(emrFileData);

                List<EmrFileData> subEmrFileDataList = emrFileData.getEmrFileDataList();
                int j = subEmrFileDataList.size();
                while (--j >= 0) {
                    subEmrFileDataList.get(j).getFileIndexDataEntity().setSortId(j + 1);
                    subEmrFileDataList.get(j).getFileIndexDataEntity().setParentFileIndexDataId(dataEntity.getFileIndexDataId());
                    stack.push(subEmrFileDataList.get(j));
                }
            }
        }
        return dataList;
    }

    private boolean isDiag(String varCode) {
        return CHUBUZHENDUAN.equals(varCode) || RUYUANZHENDUAN.equals(varCode) || FileIndexService.CHUYUANZHENDUAN.equals(varCode);
    }

    private void updateCorrectDiag(EmrFileData correctEmrFileData, EmrFileIndexEntity emrFileIndex, String correctUsername, String correctUserpwd) {
        if (!StringUtils.hasLength(correctUsername)) {
            throw new ServiceException("请提供修正诊断医师账号。");
        }
        if (!StringUtils.hasLength(correctUserpwd)) {
            throw new ServiceException("请提供修正诊断医师密码。");
        }
        Map<String, String> correctUser = fileIndexMapper.getSysUser(correctUsername);
        if (correctUser == null || correctUser.isEmpty()) {
            throw new ServiceException("修正诊断医师账号不存在。");
        }
        if (!passwordEncoder.matches(correctUserpwd, correctUser.get("userPwd"))) {
            throw new ServiceException("密码错误。");
        }
        // 查找入院病历的修正诊断节点
        FileIndexDataEntity correctDiagEntity = fileIndexMapper.getCorrectDiagId(emrFileIndex.getInpatNum());
        if (correctDiagEntity == null) {
            throw new ServiceException("修正诊断不存在，或者入院病历还未生成。");
        }
        // 检查医生等级
        int correctLevel = fileIndexMapper.queryLevel(correctUser.get("userId"));
        Integer topLevel = fileIndexMapper.queryExistCorrectSignLevel(correctDiagEntity.getEmrFileId());
        if (topLevel == null) {
            topLevel = fileIndexMapper.queryTopSignLevel(emrFileIndex.getInpatNum(), emrFileIndex.getEmrFileId());
        }
        if (correctLevel < topLevel) {
            throw new ServiceException("修正诊断账号医师职称过低，无法修正。");
        }
        fileIndexDataEntityMapper.deleteNodes(correctDiagEntity.getEmrFileId(), correctDiagEntity.getFileIndexDataId());
        //删除打印表中内容
        FilePrintContentEntity printContentEntity = new FilePrintContentEntity();
        printContentEntity.setEmrFileId(correctDiagEntity.getEmrFileId());
        filePrintContentMapper.delete(printContentEntity);
        List<EmrFileData> emrFileDataList = correctEmrFileData.getEmrFileDataList();
        Stack<EmrFileData> stack = new Stack<>();
        // 更新入院病历中的修正诊断
        Timestamp currentTime = new Timestamp(System.currentTimeMillis());
        List<FileIndexDataEntity> dataList = new ArrayList<>();
        for (int i = 0; i < emrFileDataList.size(); i++) {
            EmrFileData topEmrFileData = emrFileDataList.get(i);
            topEmrFileData.getFileIndexDataEntity().setParentFileIndexDataId(correctDiagEntity.getFileIndexDataId());
            topEmrFileData.getFileIndexDataEntity().setSortId(i + 1);
            stack.push(topEmrFileData);

            while (!stack.empty()) {
                EmrFileData emrFileData = stack.pop();
                FileIndexDataEntity dataEntity = new FileIndexDataEntity();
                BeanUtils.copyProperties(emrFileData.getFileIndexDataEntity(), dataEntity);
                dataEntity.setGmtCreate(currentTime);
                dataEntity.setGmtModify(currentTime);
                dataEntity.setFileIndexDataId(UUIDUtil.randomString());
                dataEntity.setDatasetId("");
                if (dataEntity.getDataCode() == null) {
                    dataEntity.setDataCode("");
                }
                if (dataEntity.getDataValue() == null) {
                    dataEntity.setDataValue("");
                }
                if (dataEntity.getMedicalId() == null) {
                    dataEntity.setMedicalId("");
                }
                dataEntity.setParentElementId("");
                dataEntity.setQuoteDatasetId("");
                dataEntity.setQuoteElementId("");
                dataEntity.setQuoteTplDetailId("");
                dataEntity.setBaseTplDetailId("");
                dataEntity.setGroupNo("");
                dataEntity.setUnit("");
                dataList.add(dataEntity);
                List<EmrFileData> subEmrFileDataList = emrFileData.getEmrFileDataList();
                int j = subEmrFileDataList.size();
                while (--j >= 0) {
                    EmrFileData subEmrFileData = subEmrFileDataList.get(j);
                    subEmrFileData.getFileIndexDataEntity().setSortId(j + 1);
                    subEmrFileData.getFileIndexDataEntity().setParentFileIndexDataId(dataEntity.getFileIndexDataId());
                    stack.push(subEmrFileData);
                }
            }
        }
        // 更新诊断
        if (!dataList.isEmpty()) {
            SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
            Map<String, Object> params = new HashMap<>();
            params.put("fileIndex", fileIndexEntityMapper.selectByPrimaryKey(correctDiagEntity.getEmrFileId()));
            for (FileIndexDataEntity model : dataList) {
                params.put("dataEntity", model);
                if (model.getDataValue() == null || model.getDataValue().length() < 1000) {
                    session.insert("com.haoze.nurse.dao.FileIndexDataEntityMapper.insertDataListWithInlineClob", params);
                } else {
                    session.insert("com.haoze.nurse.dao.FileIndexDataEntityMapper.insertDataListWithIndependentClob", params);
                }
            }
            session.flushStatements();
            session.close();
        }
        // 定位并更新签名时间
        fileIndexMapper.updateSign(correctDiagEntity.getEmrFileId(), correctUser);
        // 清除入院病历缓存
        if (!PROFILE_DEV.equals(activeProfile) && redisUtil.hasKey(correctDiagEntity.getEmrFileId())) {
            redisUtil.remove(correctDiagEntity.getEmrFileId());
        }
    }

    /**
     * 保存妊娠风险等级取最新的
     *
     * @param emrFileIndex
     */
    private void updatePregnancyDangerLevel(EmrFileIndexEntity emrFileIndex) {
        String healthNum = fileIndexDataEntityMapper.getHealthNumByInpatNum(emrFileIndex.getInpatNum());
        Integer count = fileIndexDataEntityMapper.getPatientCount(healthNum);
        if (count == 0) {
            fileIndexDataEntityMapper.insertIntoPatient(healthNum);
        }
        fileIndexDataEntityMapper.updateLastPatientLevel(healthNum);
    }

    /**
     * 推送孕妇分娩信息至妇幼系统
     *
     * @param fileId
     */
    public void pushToSystem(String fileId) {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setConnectionRequestTimeout(3000);
        factory.setConnectTimeout(5000);
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
        HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
        RestTemplate restTemplate = new RestTemplate(factory);
        Map<String, String> params = new HashMap<String, String>();
        params.put("fileId", fileId);
        String url = fileIndexMapper.getGyneUrl();
        try {
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class, params);
            JSONObject result = JSONObject.parseObject(response.getBody());
            logger.info("{} 孕妇分娩推送成功：{}", fileId, result.toJSONString());
        } catch (Exception e) {
            logger.info("{} 孕妇分娩推送失败", fileId);
            logger.error("失败原因", e);
        }
    }

    private EmrFile getDataFromDB(EmrFileIndexEntity emrFileIndex,String showINOUT) {
        EmrFile emrFile;
        emrFile = new EmrFile();
        emrFile.setEmrFileIndexEntityOld(emrFileIndex);
//        emrFile.setEmrType(fileIndexMapper.getEmrType(emrFileIndex.getEmrFileId()));
//        emrFile.setPrintType(fileIndexMapper.getPrintType(emrFileIndex.getEmrFileId()));
        Map<String, String> user = fileIndexMapper.getUser(emrFileIndex.getDoctorId());
        if (user != null) {
            emrFile.setGroupName(user.get("groupName"));
            emrFile.setUserName(user.get("userName"));
        }
//
//        List<Map<String, String>> observations = fileIndexMapper.queryAllObservations(emrFileIndex.getInpatNum(), null);
//        emrFile.setObservations(observations);
        emrFile.setObservations(new ArrayList<>());
        List<EmrFileData> list;
        if (FILE_STATUS_DELETE.equals(emrFileIndex.getStatus())) {
            list = getDeletedEmrFileData(emrFileIndex);
            List<EmrFileData> topList = buildTreeData(list, null);
            emrFile.setEmrFileDataList(topList);
        } else {
            list = getEmrFileData(emrFileIndex.getEmrFileId(), null,showINOUT);
            List<EmrFileData> topList = buildTreeData(list, null);
            emrFile.setEmrFileDataList(topList);
        }
        return emrFile;
    }

    /**
     * 查询被删除的病历数据列表
     *
     * @param emrFileIndex 病历ID
     * @return
     */
    private List<EmrFileData> getDeletedEmrFileData(EmrFileIndexEntity emrFileIndex) {
        long t1 = System.currentTimeMillis();
        List<Map<String, Object>> list = fileIndexEntityMapper.getAllDeletedFileIndexDataEntity(emrFileIndex);
        long t2 = System.currentTimeMillis();
        logger.info("{} 从数据库获取{}条数据时间： {} ms", emrFileIndex.getEmrFileId(), list.size(), t2 - t1);
        List<EmrFileData> emrFileDataList = convertData(list);
        emrFileDataList.parallelStream().forEach(emrFileData -> {
            Element element = emrFileData.getElement();
            element.setMedicalId(emrFileData.getFileIndexDataEntity().getMedicalId());
            // 补充全部勾选项
            if (element.getElementPropertyFormat() != null && element.getElementPropertyFormat().indexOf("\"formatValue\":\"2\"") > -1) {
                element.setSelections(fileIndexMapper.getAllSelections(element.getId()));
            }
        });
        return emrFileDataList;
    }

    private void updateElement(EmrFile emrFile) {
        Stack<EmrFileData> stack = new Stack();
        for (int i = 0; i < emrFile.getEmrFileDataList().size(); i++) {
            EmrFileData topEmrFileData = emrFile.getEmrFileDataList().get(i);
            stack.push(topEmrFileData);
            while (!stack.empty()) {
                EmrFileData emrFileData = stack.pop();
                emrFileData.setFirstQuote(false);
                emrFileData.setFirstTrigger(false);
                Element element = emrFileData.getElement();
                if (emrFileData.getEmrFileDataList().size() > 0) {
                    element.setMedicalId(emrFileData.getFileIndexDataEntity().getMedicalId());
                    for (EmrFileData subEmrFileData : emrFileData.getEmrFileDataList()) {
                        stack.push(subEmrFileData);
                    }
                }
            }
        }
    }



    @Override
    public Result getListHead(String tplId) {
        String headTplId = fileIndexMapper.getHeadTplId(tplId);
        List<EmrTemplateData> emrFileDataList = getEmrTemplateData(headTplId, null);
        List<EmrTemplateData> topList = buildTreeData2(emrFileDataList, null);
        return ResultGenerator.genOkResult(topList);

//        List<TableHeader> headers = new ArrayList<>();
//        // 获取需要列显示的模板一维数据
//        List<EmrTemplateDetailEntity> tplDetails = fileIndexMapper.getHeadTemplateDetail(PARAM, tplId);
//        if (tplDetails.isEmpty()) {
//            return ResultGenerator.genOkResult(headers);
//        }
//        for (EmrTemplateDetailEntity tplDetail : tplDetails) {
//            JSONObject jsonObject = JSONObject.parseObject(tplDetail.getElementProperty());
//            TableHeader tableHeader = new TableHeader();
//            tableHeader.setProps(tplDetail.getElementId());
//            tableHeader.setTdTableNode(jsonObject.getString("tdTableNode"));
//            tableHeader.setTdTableNodeWidth(jsonObject.getInteger("tdTableNodeWidth"));
//            tableHeader.setListNum(jsonObject.getInteger("listNum"));
//            tableHeader.setListWarn(jsonObject.getString("listWarn"));
//            tableHeader.setParentTableNodeId(jsonObject.getString("parentTableNodeId"));
//            tableHeader.setElementId(tplDetail.getElementId());
//            tableHeader.setShowChildren(jsonObject.getString("showChildren"));
//            tableHeader.setMultiRow(jsonObject.getString("multiRow"));
//            tableHeader.setNotFree(jsonObject.getString("notFree"));
//            headers.add(tableHeader);
//        }
//        List<TableHeader> fileDatalist = createBuildTreeData(headers, "0");
//        return ResultGenerator.genOkResult(fileDatalist);
    }

    private List<TableHeader> createBuildTreeData(List<TableHeader> list, String parentDetailId) {
        List<TableHeader> topList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            TableHeader node = list.get(i);
            if (node.getParentTableNodeId() != null
                    && node.getParentTableNodeId().equals(parentDetailId)) {
                topList.add(node);
                continue;
            }
            for (int j = 0; j < list.size(); j++) {
                TableHeader parent = list.get(j);
                if (parent.getElementId().equals(node.getParentTableNodeId())) {
                    parent.getChildren().add(node);
                    break;
                }
            }
        }
        topList.sort(Comparator.comparingInt(TableHeader::getListNum));
        return topList;
    }

    @Override
    public Result getDetailList(String tplId, String inpatNum, String strTm, String endTm, Integer page, Integer pageSize,String isDesc) {
        List<EmrFile> result = new ArrayList<>();
        PageHelper.startPage(page, pageSize);
        List<Map<String,String>> indexEntityList = fileIndexMapper.querySameTplFileIndex(inpatNum, tplId, strTm, endTm,isDesc);
        PageInfo<Map<String,String>> pageInfo1 = new PageInfo<>(indexEntityList);
        for (Map<String,String> map : indexEntityList) {
            EmrFile emrFile = getFileIndex(map.get("emrFileId"),NurseEnum.SHOW_INOUT_YES.getIndex());
            emrFile.setCareType(map.get("careType"));
            result.add(emrFile);
        }
        PageInfo<EmrFile> pageInfo = new PageInfo<>(result);
        pageInfo.setTotal(pageInfo1.getTotal());
        return ResultGenerator.genOkResult(pageInfo);
    }

    @Override
    public Result getNurseFileTree(String inpatNum) {
        List<Tree<Void>> totalList = new ArrayList<>();
        List<Tree<Void>> nurseFileList;
        List<Tree<Void>> reviewFileList;

        List<Map<String, String>> nurseFile = fileIndexMapper.getNurseFileTree(inpatNum, NurseEnum.IS_REVIEW_NO.getIndex());
        if(!CollectionUtils.isEmpty(nurseFile)){
            nurseFileList = nurseFile.stream().map(obj->{
                Tree<Void> tree = new Tree<>();
                tree.setId(obj.get("tplId"));
                tree.setText(obj.get("tplName"));
                tree.setType("tpl");
                return tree;
            }).collect(Collectors.toList());
            Tree<Void> rootNode = new Tree<>();
            rootNode.setId(UUIDUtil.randomString());
            rootNode.setText("护理记录");
            rootNode.setChildren(nurseFileList);
            totalList.add(rootNode);
        }

        List<Map<String, String>> reviewFile = fileIndexMapper.getNurseFileTree(inpatNum, NurseEnum.IS_REVIEW_YES.getIndex());
        if(!CollectionUtils.isEmpty(reviewFile)){
            reviewFileList = reviewFile.stream().map(obj->{
                Tree<Void> tree = new Tree<>();
                tree.setId(obj.get("tplId"));
                tree.setText(obj.get("tplName"));
                tree.setType("tpl");
                return tree;
            }).collect(Collectors.toList());

            Tree<Void> rootNode = new Tree<>();
            rootNode.setId(UUIDUtil.randomString());
            rootNode.setText("项目名称");
            rootNode.setChildren(reviewFileList);
            totalList.add(rootNode);
        }

        Tree<Void> rootNode = new Tree<>();
        rootNode.setId(UUIDUtil.randomString());
        rootNode.setText("病历目录");
        rootNode.setChildren(totalList);

        return ResultGenerator.genOkResult(rootNode);
    }

    @Override
    public Result getTplDetail(String tplDetailId,String tplId) {
        List<EmrTemplateData> emrFileDataList = getEmrTemplateData(tplId, tplDetailId);
        emrFileDataList.stream().forEach(emrTemplateData -> {
            Element element = emrTemplateData.getElement();
            // 补充全部勾选项
            if (element.getElementPropertyFormat() != null && element.getElementPropertyFormat().contains("\"formatValue\":\"2\"")) {
                element.setSelections(fileIndexMapper.getAllSelections(element.getId()));
            }
        });
        List<EmrTemplateData> topList = buildTreeData2(emrFileDataList, tplDetailId);
        return  ResultGenerator.genOkResult(topList);
    }

    /**
     * 查询病历数据列表
     *
     * @param tplId             模板ID
     * @param parentFileIndexDataId 父级数据ID 可以为null
     * @return
     */
    public List<EmrTemplateData> getEmrTemplateData(String tplId, String parentFileIndexDataId) {
        List<Map<String, Object>> list = tplDetailMapper.getAllTemplateDetailList(tplId, parentFileIndexDataId);
        return convertData2(list);
    }

    /**
     * 数据格式转换
     * @param list
     * @return
     */
    private List<EmrTemplateData> convertData2(List<Map<String, Object>> list) {
        return list.parallelStream().map(map -> {
            EmrTemplateData data = new EmrTemplateData();
            EmrTemplateDetailVO dataEntity = new EmrTemplateDetailVO();
            dataEntity.setTplDetailId((String) map.get("TPL_DETAIL_ID"));
            dataEntity.setDatasetId((String) map.get("DATASET_ID"));
            dataEntity.setElementRemark((String) map.get("ELEMENT_REMARK"));
            dataEntity.setBaseTplDetailId((String) map.get("BASE_TPL_DETAIL_ID"));
            dataEntity.setTplId((String) map.get("TPL_ID"));
            dataEntity.setSortId(((Number) map.get("SORT_ID")).intValue());
            dataEntity.setElementId((String) map.get("ELEMENT_ID"));
            dataEntity.setParentElementId((String) map.get("PARENT_ELEMENT_ID"));
            dataEntity.setQuoteDatasetId((String) map.get("QUOTE_DATASET_ID"));
            dataEntity.setQuoteElementId((String) map.get("QUOTE_ELEMENT_ID"));
            dataEntity.setDataCode((String) map.get("DATA_CODE"));
            dataEntity.setParentTplDetailId((String) map.get("PARENT_TPL_DETAIL_ID"));
            dataEntity.setQuoteTplDetailId((String) map.get("QUOTE_TPL_DETAIL_ID"));
            dataEntity.setQuoteDetailType(map.get("QUOTE_DETAIL_TYPE") == null ? "0" : map.get("QUOTE_DETAIL_TYPE").toString());
            String dataValue = "";
            try {
                if (map.get("DATA_VALUE") != null) {
                    if (map.get("DATA_VALUE") instanceof Clob) {
                        Clob clob = (Clob) map.get("DATA_VALUE");
                        BufferedReader reader = new BufferedReader(clob.getCharacterStream());
                        dataValue = FileCopyUtils.copyToString(reader);
                    } else {
                        dataValue = (String) map.get("DATA_VALUE");
                    }
                }
            } catch (SQLException | IOException e) {
                logger.error("转换对象出错。", e);
            }
            dataEntity.setDataValue(dataValue);
            dataEntity.setPrintIdentification((String) map.get("PRINT_IDENTIFICATION"));
            dataEntity.setShowIdentification((String) map.get("SHOW_IDENTIFICATION"));
            dataEntity.setDeleteIdentification((String) map.get("DELETE_IDENTIFICATION"));
            dataEntity.setMedicalId((String) map.get("MEDICAL_ID"));
            dataEntity.setUpdateFlag(map.get("UPDATE_FLAG") == null ? StateEnum.READ_FLAG.getValue() : map.get("UPDATE_FLAG").toString());
            dataEntity.setClassNameId((String) map.get("CLASS_NAME_ID"));
            dataEntity.setElementProperty(map.get("ELEMENT_PROPERTY") == null ? null : map.get("ELEMENT_PROPERTY").toString());
            dataEntity.setDataNo(map.get("DATA_NO") == null ? null : map.get("DATA_NO").toString());
            dataEntity.setDeletable(map.get("DELETABLE") == null ? "0" : map.get("DELETABLE").toString());
            dataEntity.setUnit(map.get("UNIT") == null ? "" : map.get("UNIT").toString());

            data.setFileIndexDataEntity(dataEntity);
            Element element = new Element();
            element.setId((String) map.get("ELEMENT_ID"));
            element.setName((String) map.get("ELEMENT_NAME"));
            element.setType((String) map.get("ELEMENT_DATA_TYPE_ID"));
            element.setMin(map.get("MIN_VALUE") == null ? null : ((Number) map.get("MIN_VALUE")).doubleValue());
            element.setMax(map.get("MAX_VALUE") == null ? null : ((Number) map.get("MAX_VALUE")).doubleValue());
            element.setUnit(map.get("ELEMENT_UNIT") == null ? "" : map.get("ELEMENT_UNIT").toString());
            element.setVarCode((String) map.get("VAR_CODE"));
            element.setValue(dataValue);
            element.setDataCode((String) map.get("DATA_CODE"));
            element.setDataValue(dataValue);
            element.setElementPropertyFormat((String) map.get("ELEMENT_PROPERTY_FORMAT"));
            element.setMedicalId(dataEntity.getMedicalId());
            data.setElement(element);
            data.setEmrFileDataList(new ArrayList<>());
            return data;
        }).collect(Collectors.toList());
    }

    /**
     * 构造病历数据树
     *
     * @param list                  病历数据
     * @param parentDetailId 顶级数据节点ID 可以为null
     * @return
     */
    private List<EmrTemplateData> buildTreeData2(List<EmrTemplateData> list, String parentDetailId) {
        List<EmrTemplateData> topList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            EmrTemplateData node = list.get(i);
            node.setEmrFileDataList(new ArrayList<>());
            if (node.getFileIndexDataEntity().getParentTplDetailId() == null
                    || node.getFileIndexDataEntity().getParentTplDetailId().equals(parentDetailId)) {
                topList.add(node);
                continue;
            }
            for (int j = 0; j < i; j++) {
                EmrTemplateData parent = list.get(j);
                if (parent.getFileIndexDataEntity().getTplDetailId().equals(node.getFileIndexDataEntity().getParentTplDetailId())) {
                    parent.getEmrFileDataList().add(node);
                    break;
                }
            }
        }
        return topList;
    }


    @Override
    public Result getRealize(String inpatNum, String tplId) {
        List<String> realizeList = fileIndexMapper.getRealize(inpatNum, tplId);
        return ResultGenerator.genOkResult(realizeList);
    }

    @Override
    public DoctorAdvicesVO queryOrders(String inpatNum, String classId, String type, String status, String startDate, String endDate, Integer page, Integer size) {
        // TODO： classId 对应 SYSMN.SYS_PRIMARY_DATA_VALUE表 DATA_VALUE 字段
        //  7F8AF946D8917555E0537A5B14ACC42E 临时医嘱 1，
        //  7F8AF94691897555E0537A5B14ACC42E 长期医嘱 2，
        //  7F8AF946918A7555E0537A5B14ACC42E 其他 9

        // 默认采用开始时间
        type = OrderTimeTypeEnum.StartTime.getEnumValue();

        Date beginDate = null;
        Date theEndDate = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        if (!startDate.equals("")) {
            long startDateStr = Long.parseLong(startDate);

            String str1 = sdf.format(startDateStr * 1000);
            try {
                beginDate = sdf.parse(str1);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }

        if (!endDate.equals("")) {
            long endDateStr = Long.parseLong(endDate);

            String str2 = sdf.format((endDateStr + 24*60*60) * 1000);
            try {
                theEndDate = sdf.parse(str2);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }

        Integer startNum = (page - 1) * size;
        Integer endNum = page * size;

        Long sum = 0l;
        List<Map<String, String>> list = new ArrayList<>();

        // 1 临时医嘱，2 长期医嘱，9 全部医嘱
        // 1 全部医嘱, 2 新开医嘱，3 整理医嘱，4 已停医嘱
        String ordersClassId = "";
        if (classId.equals(OrderTypeEnum.Temporary.getEnumValue())) { // 临时医嘱 只查临时
            ordersClassId = "7F8AF946D8917555E0537A5B14ACC42E";
            if (status.equals(OrderStatusTypeEnum.All.getEnumValue())) {
                sum = nurseOrdersMapper.queryOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate);
                list = nurseOrdersMapper.queryOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum);
            } else if (status.equals(OrderStatusTypeEnum.NewOpen.getEnumValue())) { // 新开
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 0);
                beginDate = calendar.getTime();
                calendar.set(Calendar.HOUR_OF_DAY, 24);
                theEndDate = calendar.getTime();
                //System.out.println("beginDate = " + beginDate + " ; " + "endDate = " + theEndDate);
                // 开立时间0:00~24:00范围内的长期和临时医嘱
                sum = nurseOrdersMapper.queryNewOpenOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate);
                list = nurseOrdersMapper.queryNewOpenOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum);
            } else if (status.equals(OrderStatusTypeEnum.Arrange.getEnumValue())) { // 整理
                // 整理医嘱只查询长期，所以返回空
                sum = 0l;
                list = new ArrayList<>();
            } else if (status.equals(OrderStatusTypeEnum.Stoped.getEnumValue())) { // 已停
                // 当前时间
                Date currDate = new Date();
                sum = nurseOrdersMapper.queryAllStopedOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate, currDate);
                list = nurseOrdersMapper.queryAllStopedOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum, currDate);
            } else { // 全部
                sum = nurseOrdersMapper.queryOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate);
                list = nurseOrdersMapper.queryOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum);
            }


        } else if (classId.equals(OrderTypeEnum.LongTerm.getEnumValue())) { // 长期医嘱 只查长期
            ordersClassId = "7F8AF94691897555E0537A5B14ACC42E";
            if (status.equals(OrderStatusTypeEnum.All.getEnumValue())) {
                sum = nurseOrdersMapper.queryOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate);
                list = nurseOrdersMapper.queryOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum);
            } else if (status.equals(OrderStatusTypeEnum.NewOpen.getEnumValue())) { // 新开
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 0);
                beginDate = calendar.getTime();
                calendar.set(Calendar.HOUR_OF_DAY, 24);
                theEndDate = calendar.getTime();
                //System.out.println("beginDate = " + beginDate + " ; " + "endDate = " + theEndDate);
                // 开立时间0:00~24:00范围内的长期和临时医嘱
                sum = nurseOrdersMapper.queryNewOpenOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate);
                list = nurseOrdersMapper.queryNewOpenOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum);
            } else if (status.equals(OrderStatusTypeEnum.Arrange.getEnumValue())) { // 整理
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                /*calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);*/
                calendar.set(Calendar.SECOND, 0);
                Date nodeDate = calendar.getTime();
                sum = nurseOrdersMapper.queryArrangeOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate, nodeDate);
                list = nurseOrdersMapper.queryArrangeOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum, nodeDate);
            } else if (status.equals(OrderStatusTypeEnum.Stoped.getEnumValue())) { // 已停
                // 当前时间
                Date currDate = new Date();
                sum = nurseOrdersMapper.queryAllStopedOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate, currDate);
                list = nurseOrdersMapper.queryAllStopedOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum, currDate);
            } else { // 全部
                sum = nurseOrdersMapper.queryOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate);
                list = nurseOrdersMapper.queryOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum);
            }


        } else if (classId.equals(OrderTypeEnum.All.getEnumValue())) { // 全部医嘱 查询全部
            ordersClassId = "";
            if (status.equals(OrderStatusTypeEnum.All.getEnumValue())) {
                sum = nurseOrdersMapper.queryAllOrdersSum(inpatNum, type, beginDate, theEndDate);
                list = nurseOrdersMapper.queryAllOrders(inpatNum, type, beginDate, theEndDate, startNum, endNum);
            } else if (status.equals(OrderStatusTypeEnum.NewOpen.getEnumValue())) { // 新开
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 0);
                beginDate = calendar.getTime();
                calendar.set(Calendar.HOUR_OF_DAY, 24);
                theEndDate = calendar.getTime();
                //System.out.println("beginDate = " + beginDate + " ; " + "endDate = " + theEndDate);
                // 开立时间0:00~24:00范围内的长期和临时医嘱
                sum = nurseOrdersMapper.queryNewOpenOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate);
                list = nurseOrdersMapper.queryNewOpenOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum);
            } else if (status.equals(OrderStatusTypeEnum.Arrange.getEnumValue())) { // 整理
                ordersClassId = "7F8AF94691897555E0537A5B14ACC42E";
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                /*calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);*/
                calendar.set(Calendar.SECOND, 0);
                Date nodeDate = calendar.getTime();
                sum = nurseOrdersMapper.queryArrangeOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate, nodeDate);
                list = nurseOrdersMapper.queryArrangeOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum, nodeDate);
            } else if (status.equals(OrderStatusTypeEnum.Stoped.getEnumValue())) { // 已停
                // 当前时间
                Date currDate = new Date();
                sum = nurseOrdersMapper.queryAllStopedOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate, currDate);
                list = nurseOrdersMapper.queryAllStopedOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum, currDate);
            } else { // 全部
                sum = nurseOrdersMapper.queryOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate);
                list = nurseOrdersMapper.queryOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum);
            }

        } else { //

            ordersClassId = "";
            if (status.equals(OrderStatusTypeEnum.All.getEnumValue())) {
                sum = nurseOrdersMapper.queryAllOrdersSum(inpatNum, type, beginDate, theEndDate);
                list = nurseOrdersMapper.queryAllOrders(inpatNum, type, beginDate, theEndDate, startNum, endNum);
            } else if (status.equals(OrderStatusTypeEnum.NewOpen.getEnumValue())) { // 新开
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 0);
                beginDate = calendar.getTime();
                calendar.set(Calendar.HOUR_OF_DAY, 24);
                theEndDate = calendar.getTime();
                //System.out.println("beginDate = " + beginDate + " ; " + "endDate = " + theEndDate);
                // 开立时间0:00~24:00范围内的长期和临时医嘱
                sum = nurseOrdersMapper.queryNewOpenOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate);
                list = nurseOrdersMapper.queryNewOpenOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum);
            } else if (status.equals(OrderStatusTypeEnum.Arrange.getEnumValue())) { // 整理
                ordersClassId = "7F8AF94691897555E0537A5B14ACC42E"; // 整理类型只查长期医嘱
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                /*calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);*/
                calendar.set(Calendar.SECOND, 0);
                Date nodeDate = calendar.getTime();
                sum = nurseOrdersMapper.queryArrangeOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate, nodeDate);
                list = nurseOrdersMapper.queryArrangeOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum, nodeDate);
            } else if (status.equals(OrderStatusTypeEnum.Stoped.getEnumValue())) { // 已停
                // 当前时间
                Date currDate = new Date();
                sum = nurseOrdersMapper.queryAllStopedOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate, currDate);
                list = nurseOrdersMapper.queryAllStopedOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum, currDate);
            } else { // 全部
                sum = nurseOrdersMapper.queryOrdersSum(inpatNum, ordersClassId, type, beginDate, theEndDate);
                list = nurseOrdersMapper.queryOrders(inpatNum, ordersClassId, type, beginDate, theEndDate, startNum, endNum);
            }
        }

        DoctorAdvicesVO doctorAdvicesVO = new DoctorAdvicesVO();
        doctorAdvicesVO.setSum(String.valueOf(sum));
        //补全小数点前0
        DecimalFormat df = new DecimalFormat("#.####");
        doctorAdvicesVO.setLists(list.stream().map(obj->{
            if(obj.get("itemDosage") != null){
                obj.put("itemDosage",df.format(Double.parseDouble(obj.get("itemDosage"))));
            }
            return obj;
        }).collect(Collectors.toList()));

        //System.out.println("doctor = " + doctorAdvicesVO);

        return doctorAdvicesVO;
    }

    @Override
    public Result getEmrFileId(String inpatNum) {
        //根据住院号获取病案首页护理附页文书ID
        String emrType = "108";
        String emrFileId = fileIndexMapper.getEmrFileId(inpatNum,emrType);
        return ResultGenerator.genOkResult(emrFileId);
    }
}
